package org.springblade.thingsphere.network.components.http.server;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.api.R;
import org.springblade.thingsphere.CompositeProtocolSupport;
import org.springblade.thingsphere.domain.Message;
import org.springblade.thingsphere.manage.pojo.entity.GatewayEntity;
import org.springblade.thingsphere.manage.service.IGatewayService;
import org.springblade.thingsphere.message.DeviceMessageCodec;
import org.springblade.thingsphere.network.components.NetworkProvider;
import org.springblade.thingsphere.network.components.NetworkType;
import org.springblade.thingsphere.network.components.bus.event.HttpServerMsgEvent;
import org.springblade.thingsphere.network.components.common.HttpServerConfig;
import org.springblade.thingsphere.network.protocol.impl.ProtocolAssetSupplier;
import org.springblade.thingsphere.type.DefaultTransport;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lhb
 * @date 2024/9/29 下午5:52
 */
@Slf4j
@Component
public class VertxHttpServer implements NetworkProvider<HttpServerConfig, HttpServer> {

	@Resource
	private Vertx vertx;
	@Resource
	private ApplicationEventPublisher applicationEventPublisher;
	@Resource
	private IGatewayService gatewayService;
	@Resource
	private ProtocolAssetSupplier protocolAssetSupplier;

	private static final Map<Long, HttpServer> HTTP_SERVER_MAP = new ConcurrentHashMap<>();
	private static final Map<Long, Router> ROUTER_MAP = new ConcurrentHashMap<>();

	@Override
	public NetworkType getType() {
		return NetworkType.HTTP_SERVER;
	}

	@Override
	public HttpServer createNetwork(HttpServerConfig httpServerConfig) {

		log.info("【 Load the Http Server network component 】config:{}", httpServerConfig);

		if (HTTP_SERVER_MAP.containsKey(httpServerConfig.getId())) {
			return HTTP_SERVER_MAP.get(httpServerConfig.getId());
		}

		if (!NetUtil.isUsableLocalPort(httpServerConfig.getPort())) {
			throw new ServiceException("port unavailable");
		}

		// 创建一个路由器
		Router router = Router.router(vertx);
		// 设置post网络组件
		router.route().handler(BodyHandler.create());

		// 处理设备上报属性
		router.post(httpServerConfig.getReportPropertyPath()).handler(handler -> {
			JsonObject bodyAsJson = handler.getBodyAsJson();
			if (null == bodyAsJson || bodyAsJson.isEmpty()) {
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.status(false)));
				return;
			}

			// 查询网络组件对应的网关
			GatewayEntity gateway = gatewayService.dictByNetworkId(httpServerConfig.getId());
			if (null == gateway || 0 == gateway.getStatus()) {
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.fail("未找到对应的设备网关")));
				return;
			}
			// 调用协议包解析请求的内容
			CompositeProtocolSupport compositeProtocolSupport = protocolAssetSupplier.getProtocolSupportById(gateway.getProtocolId());
			if (null == compositeProtocolSupport) {
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.fail("未找到处理的协议")));
				return;
			}
			DeviceMessageCodec deviceMessageCodec = compositeProtocolSupport.getMessageCodecSupports().get(DefaultTransport.HTTP.getId());
			if (null == deviceMessageCodec) {
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.fail("未找到对应HTTP协议包实现")));
				return;
			}
			List<Message> decoder = deviceMessageCodec.decoder(bodyAsJson.toString());

			// 将内容发送到总线bus
			applicationEventPublisher.publishEvent(new HttpServerMsgEvent<>(this, decoder));

			handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.status(true)));
		});

		// TODO 处理固件更新回馈
		if (StrUtil.isNotBlank(httpServerConfig.getFirmwareProgressPath())) {
			router.post(httpServerConfig.getFirmwareProgressPath()).handler(handler -> {
				JsonObject bodyAsJson = handler.getBodyAsJson();
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.status(true)));
			});
		}

		// TODO 处理固件更新拉取
		if (StrUtil.isNotBlank(httpServerConfig.getFirmwarePullPath())) {
			router.post(httpServerConfig.getFirmwarePullPath()).handler(handler -> {
				JsonObject bodyAsJson = handler.getBodyAsJson();
				handler.response().putHeader("content-type", "application/json").end(JSONObject.toJSONString(R.status(true)));
			});
		}

		// 创建 HTTP 服务器并绑定路由
		HttpServer httpServer = vertx.createHttpServer()
			.requestHandler(router)
			.listen(httpServerConfig.getPort(), http -> {
				if (http.succeeded()) {
					log.info("HTTP server started on port {}", httpServerConfig.getPort());
				} else {
					log.error("Failed to start HTTP server: ", http.cause());
				}
			});

		ROUTER_MAP.put(httpServerConfig.getId(), router);
		HTTP_SERVER_MAP.put(httpServerConfig.getId(), httpServer);
		return httpServer;
	}

	@Override
	public void shutdown(Long id) {
		Router router = ROUTER_MAP.get(id);
		if (null != router) {
			router.clear();
			ROUTER_MAP.remove(id);
		}

		HttpServer httpServer = HTTP_SERVER_MAP.get(id);
		if (null != httpServer) {
			httpServer.close();
			HTTP_SERVER_MAP.remove(id);
		}
	}
}
